<html>
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="canonical" href="./Pipeline_Handshake_Multiplier.html">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Accepts one ready/valid handshake at its input, along with a repeat count, and will not accept another input handshake until `input_data_repeat_count` output handshakes have been accepted.  Each output handshake is a copy of the input handshake, without the repeat count.">
<title>Pipeline Handshake Multiplier</title>
</head>
<body>

<p class="inline bordered"><b><a href="./Pipeline_Handshake_Multiplier.v">Source</a></b></p>
<p class="inline bordered"><b><a href="./legal.html">License</a></b></p>
<p class="inline bordered"><b><a href="./index.html">Index</a></b></p>

<h1>Pipeline Handshake Multiplier</h1>
<p>Accepts one ready/valid handshake at its input, along with a repeat count,
 and will not accept another input handshake until <code>input_data_repeat_count</code>
 output handshakes have been accepted.  Each output handshake is a copy of
 the input handshake, without the repeat count.</p>
<p><code>input_data_repeat_count</code> must be less or equal to <code>MAX_REPEAT_COUNT</code>.</p>
<p><em>Loading a repeat count of zero immediately resets the buffer, and so the
 input handshake is sunk and so no output handshakes happen, and we
 immediately are ready to accept a new input handshake.</em></p>

<pre>
`default_nettype none

module <a href="./Pipeline_Handshake_Multiplier.html">Pipeline_Handshake_Multiplier</a>
#(
    parameter WORD_WIDTH        = 0,
    parameter MAX_REPEAT_COUNT  = 0,

    // Do not set at instantiation, except in Vivado IPI.
    parameter REPEAT_COUNT_WIDTH = clog2(MAX_REPEAT_COUNT) + 1 // +1 to hold exact number, not a 0-index
)
(
    input   wire                                clock,
    input   wire                                clear,

    input   wire                                input_data_valid,
    output  wire                                input_data_ready,
    input   wire    [WORD_WIDTH-1:0]            input_data,
    input   wire    [REPEAT_COUNT_WIDTH-1:0]    input_data_repeat_count,

    output  wire                                output_data_valid,
    input   wire                                output_data_ready,
    output  wire    [WORD_WIDTH-1:0]            output_data
);

    `include "<a href="./clog2_function.html">clog2_function</a>.vh"
</pre>

<p>First, let's buffer the input handshake.  A Half Buffer will hold its
 output steady and not accept another input handshake until its output
 handshake completes. A repeat count of zero clears the buffer immediately.</p>

<pre>
    // verilator lint_off UNOPTFLAT
    wire output_data_ready_divided;
    // verilator lint_on  UNOPTFLAT

    reg clear_input_buffer = 1'b0;

    <a href="./Pipeline_Half_Buffer.html">Pipeline_Half_Buffer</a>
    #(
        .WORD_WIDTH         (WORD_WIDTH),
        .CIRCULAR_BUFFER    (0)  // non-zero to enable
    )
    input_buffer
    (
        .clock              (clock),
        .clear              (clear | clear_input_buffer),

        .input_valid        (input_data_valid),
        .input_ready        (input_data_ready),
        .input_data         (input_data),

        .output_valid       (output_data_valid),
        .output_ready       (output_data_ready_divided),
        .output_data        (output_data)
    );
</pre>

<p>We only need to control the buffer output ready signal and assert it once
 after <code>input_data_repeat_count</code> module output handshakes. The repeat count
 is stored in the Pulse Divider one cycle before the output handshake
 becomes ready.</p>

<pre>
    localparam REPEAT_ZERO = {REPEAT_COUNT_WIDTH{1'b0}};

    reg module_input_handshake_done  = 1'b0;
    reg module_output_handshake_done = 1'b0;

    always @(*) begin
        module_input_handshake_done  = (input_data_valid            == 1'b1) && (input_data_ready        == 1'b1);
        clear_input_buffer           = (module_input_handshake_done == 1'b1) && (input_data_repeat_count == REPEAT_ZERO);
        module_output_handshake_done = (output_data_valid           == 1'b1) && (output_data_ready       == 1'b1);
    end
</pre>

<p>NOTE: a <code>input_data_repeat_count</code> of zero DOES get loaded, which will cause
 the Pulse_Divider to immediately load the first non-zero value it sees, but
 since the input_buffer is not asserting valid at its output, any output
 from the Pulse_Divider cannot complete any handshakes and has no effect.</p>

<pre>
    <a href="./Pulse_Divider.html">Pulse_Divider</a>
    #(
        .WORD_WIDTH         (REPEAT_COUNT_WIDTH),
        .INITIAL_DIVISOR    (MAX_REPEAT_COUNT [REPEAT_COUNT_WIDTH-1:0])
    )
    output_handshake_counter
    (
        .clock              (clock),
        .restart            (module_input_handshake_done),
        .divisor            (input_data_repeat_count),
        .pulses_in          (module_output_handshake_done),
        .pulse_out          (output_data_ready_divided),
        // verilator lint_off PINCONNECTEMPTY
        .div_by_zero        ()
        // verilator lint_on  PINCONNECTEMPTY
    );

endmodule
</pre>

<hr>
<p><a href="./index.html">Back to FPGA Design Elements</a>
<center><a href="https://fpgacpu.ca/">fpgacpu.ca</a></center>
</body>
</html>

